package com.yanqu.road.server.manger.relatives;

import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eMailType;
import com.yanqu.road.entity.enums.ePlayerAttrType;
import com.yanqu.road.entity.enums.eSkillType;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.player.UserBeauty;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.entity.relatives.RelativesGift;
import com.yanqu.road.entity.relatives.RelativesInfo;
import com.yanqu.road.entity.relatives.RelativesLetter;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.bussiness.player.UserBeautyBussiness;
import com.yanqu.road.logic.bussiness.relatives.RelativesBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.logic.sort.RelativesLetterSort;
import com.yanqu.road.pb.relatives.RelativesProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.player.AttributeModule;
import com.yanqu.road.server.gameplayer.module.player.BeautyModule;
import com.yanqu.road.server.gameplayer.module.relatives.RelativesModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.MultipleLanguageMgr;
import com.yanqu.road.server.manger.ServerLanguageMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.curio.CurioMgr;
import com.yanqu.road.server.manger.config.SkillMgr;
import com.yanqu.road.server.manger.marriage.MarriageMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.relatives.task.AddCrossLetterNumTask;
import com.yanqu.road.server.manger.relatives.task.CancelRelativesTask;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class RelativesMgr extends TempMgr {
    /**
     * 亲家数据
     */
    private static Map<Long, Map<Long, RelativesInfo>> relativesMap;
    /**
     * 赠礼收礼数据
     */
    private static Map<Long, RelativesGift> giftMap;

    /**
     * 写信收信数据
     */
    private static Map<Long, RelativesLetter> letterMap;

    /**
     * 书信最大id
     */
    private static AtomicLong letterId;

    /**
     * 赠礼最大id
     */
    private static AtomicLong giftId;

    private static RelativesLetterSort letterSort = new RelativesLetterSort();

    public static Map<Long, RelativesGift> getGiftMap() {
        return giftMap;
    }

    /**
     * 缓存跨服亲家的信息
     */
    public static Map<Long, UserBaseInfo> cacheOtherServerUserMap = new ConcurrentHashMap<>();

    /**
     * 待同步玩家
     */
    private static Set<Long> todoGetUserSet = new HashSet<>();

    /**
     * 亲家锁
     */
    private static Object locker = new Object();

    @Override
    public boolean reloadData() {
        relativesMap = new ConcurrentHashMap<>();
        giftMap = new ConcurrentHashMap<>();
        letterMap = new ConcurrentHashMap<>();
        String serverId = ConfigHelper.getValue("serverId");
        //玩家编号15位
        while (serverId.length() < 15) {
            serverId += 0;
        }
        Long maxLetterId = RelativesBussiness.getMaxLetterId();
        if (maxLetterId == 0) {
            //玩家编号15位
            while (serverId.length() < 15) {
                serverId += 0;
            }
            letterId = new AtomicLong(Long.valueOf(serverId));
        }else {
            letterId = new AtomicLong(maxLetterId);
        }
        Long maxGiftId = RelativesBussiness.getMaxGiftId();
        if (maxGiftId == 0) {
            giftId = new AtomicLong(Long.valueOf(serverId));
        }else {
            giftId = new AtomicLong(maxGiftId);
        }
        return true;
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    @Override
    public boolean save() {
        relativesMap.forEach((k,v)-> v.forEach((k2, v2)->{
            if (v2.isInsertOption()){
                RelativesBussiness.addRelativesInfo(v2);
            } else if (v2.isUpdateOption()) {
                RelativesBussiness.updateRelativesInfo(v2);
            }
        }));

        for (RelativesGift gift : giftMap.values()) {
            if (gift.isInsertOption()) {
                RelativesBussiness.addRelativesGift(gift);
            } else if (gift.isUpdateOption()) {
                RelativesBussiness.updateRelativesGift(gift);
            }
        }
        Iterator<RelativesLetter> iterator = letterMap.values().iterator();
        while (iterator.hasNext()) {
            RelativesLetter letter = iterator.next();
            if (letter.isInsertOption()) {
                RelativesBussiness.addRelativesLetter(letter);
            } else if (letter.isUpdateOption()) {
                RelativesBussiness.updateRelativesLetter(letter);
            }
            if (letter.isDelete() && !letter.isDirty()) {//确保入库才从内存中移除
                iterator.remove();
            }
        }
        return true;
    }

    /**
     * 载入玩家数据,内存中没有数据才取数据库
     * @param userId
     */
    public static Map<Long, RelativesInfo> loadRelativesInfo(long userId) {
        List<RelativesInfo> infoList = RelativesBussiness.getRelativesInfoList(userId);
        infoList.sort((o1, o2) -> {
            if(o1.getStatus() != o2.getStatus()){
                return o2.getStatus() - o1.getStatus();
            }
            return o2.getMarriageTimes() - o1.getMarriageTimes();
        });
        Map<Long, RelativesInfo> map = new ConcurrentHashMap<>();
        for (RelativesInfo info : infoList) {
            addRelativesInfo(info);
            long userId1 = info.getUserId1();
            long userId2 = info.getUserId2();
            long relativeId;
            if (userId == userId1) {
                //map.put(userId2, relativesMap.get(userId1).get(userId2));
                //addToFetch(userId2);
                relativeId = userId2;
            } else {
                //map.put(userId1, relativesMap.get(userId1).get(userId2));
                //addToFetch(userId1);
                relativeId = userId1;
            }
            map.put(relativeId, getRelativesInfo(userId1, userId2));
            addToFetch(relativeId);
        }
        return map;
    }
    /**
     * 载入玩家赠礼数据
     * @param userId
     */
    public static void loadRelativesGift(long userId, Map<Long, RelativesGift> giveMap, Map<Long, RelativesGift> receiveMap) {
        loadRelativesGiftFromDb(userId);
        for (RelativesGift gift : giftMap.values()) {
            if (gift.getFromId() == userId) {
                giveMap.put(gift.getToId(), gift);
            } else if (gift.getToId() == userId) {
                receiveMap.put(gift.getFromId(), gift);
            }
        }
    }

    /**
     * 从数据库获取赠礼数据
     * @param userId
     */
    private static void loadRelativesGiftFromDb(long userId) {
        List<RelativesGift> gifts = RelativesBussiness.getRelativesGiftList(userId);
        for (RelativesGift gift : gifts) {
            if (!giftMap.containsKey(gift.getGiftId())) {
                giftMap.put(gift.getGiftId(), gift);
            }
        }
    }

    /**
     * 从数据库获取赠礼数据
     * @param userIdList
     */
    public static void loadRelativesGiftFromDb(List<Long> userIdList) {
        List<RelativesGift> gifts = RelativesBussiness.getRelativesGiftList(userIdList);
        for (RelativesGift gift : gifts) {
            if (!giftMap.containsKey(gift.getGiftId())) {
                giftMap.put(gift.getGiftId(), gift);
            }
        }
    }


    /**
     * 载入玩家书信数据
     * @param userId
     */
    public static Map<Long, LinkedList<RelativesLetter>> loadRelativesLetter(long userId) {
        loadRelativesLetterFromDb(userId);
        Map<Long, LinkedList<RelativesLetter>> result = new ConcurrentHashMap<>();
        for (RelativesLetter letter : letterMap.values()) {
            long relativesId = 0;
            if (letter.getFromId() == userId) {
                relativesId = letter.getToId();
            } else if (letter.getToId() == userId) {
                relativesId = letter.getFromId();
            }
            LinkedList<RelativesLetter> letters = result.get(relativesId);
            if (letters == null) {
                letters = new LinkedList<>();
                result.put(relativesId, letters);
            }
            letters.addLast(letter);
        }
        for(LinkedList<RelativesLetter> dataList : result.values()){
            dataList.sort(letterSort);
        }
        return result;
    }

    /**
     * 从数据库获取书信数据
     * @param userId
     */
    private static void loadRelativesLetterFromDb(long userId) {
        List<RelativesLetter> letters = RelativesBussiness.getRelativesLetterList(userId);
        for (RelativesLetter letter : letters) {
            if (!letterMap.containsKey(letter.getId())) {
                synchronized (letterMap) {
                    if (!letterMap.containsKey(letter.getId())) {
                        letterMap.put(letter.getId(), letter);
                    }
                }
            }
        }
    }

    public static RelativesInfo addRelativesInfo(RelativesInfo info) {
        RelativesInfo temp;
        synchronized (locker) {
            //check collection null
            if (!relativesMap.containsKey(info.getUserId1())) {
                relativesMap.put(info.getUserId1(), new ConcurrentHashMap<>());
            }
            if (!relativesMap.containsKey(info.getUserId2())) {
                relativesMap.put(info.getUserId2(), new ConcurrentHashMap<>());
            }
            //关系是否存在
            RelativesInfo old = getRelativesInfo(info.getUserId1(), info.getUserId2());
            if(old != null){
                temp = old;
                //更新, 多条记录（有错误的数据）才需要更新
                //防止同一条记录，被其他亲家加载时，覆盖了内存中的数据（未保存之前），同一条数据以内存为准
                if((info.getUserId1() != old.getUserId1()) && (info.getStatus() > old.getStatus() || info.getMarriageTimes() > old.getMarriageTimes())){
                    old.setStatus(info.getStatus());
                    old.setMarriageTimes(info.getMarriageTimes());
                    old.setIsShow(info.getIsShow());

                    //重置不要的数据，及更新
                    info.setStatus((short) 0);
                    info.setMarriageTimes(0);
                    //无效的数据（不被访问到）
                    if(info.getUserId1() < info.getUserId2()){
                        relativesMap.get(info.getUserId2()).put(info.getUserId1(), info);
                    }else {
                        relativesMap.get(info.getUserId1()).put(info.getUserId2(), info);
                    }
                }
            }else {
                //新增
                if(info.getUserId1() < info.getUserId2()) {
                    relativesMap.get(info.getUserId1()).put(info.getUserId2(), info);
                }else {
                    relativesMap.get(info.getUserId2()).put(info.getUserId1(), info);
                }
                temp = info;
            }
        }
        addToFetch(temp.getUserId2());
        addToFetch(temp.getUserId1());
        return temp;
    }

    public static RelativesInfo getRelativesInfo(long userId1, long userId2) {
        if(userId1 < userId2) {
            if (relativesMap.containsKey(userId1)) {
                if (relativesMap.get(userId1).containsKey(userId2)) {
                    return relativesMap.get(userId1).get(userId2);
                }
            }
        }else {
            if (relativesMap.containsKey(userId2)) {
                if (relativesMap.get(userId2).containsKey(userId1)) {
                    return relativesMap.get(userId2).get(userId1);
                }
            }
        }
        return null;
    }

    public static boolean isLoadUserRelatives(long userId){
        //玩家在线,登录时已经加载过亲家
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        if(player != null){
            return true;
        }
        //只有跨服使用，先热更
        if(relativesMap.containsKey(userId)){
            //跨服亲家，userId2 必然是其他区服
            //有存在其他区服的亲家，说明是玩家亲家数据加载过
            for (Map.Entry<Long, RelativesInfo> entry : relativesMap.get(userId).entrySet()) {
                if(entry.getValue().getUserId1() == userId) {
                    long userId2 = entry.getValue().getUserId2();
                    if (getUserServerId(userId2) != GameServer.getInstance().getServerId()) {
                        return true;
                    }
                }
            }
        }
//        for (Map.Entry<Long, Map<Long, RelativesInfo>> entry : relativesMap.entrySet()) {
//            if(entry.getValue().containsKey(userId)){
//                return true;
//            }
//        }
        return false;
    }

    public static int getRelativesNum(long userId) {
        int count = 0;
        for (Map<Long, RelativesInfo> map : relativesMap.values()) {
            for (RelativesInfo info : map.values()) {
                if (info.hasUserId(userId) && info.getStatus() == 1) {
                    count++;
                }
            }
        }
        return count;
    }

    public static RelativesGift createRelativesGift(long fromId, long toId) {
        RelativesGift gift = new RelativesGift();
        gift.setGiftId(giftId.incrementAndGet());
        gift.setFromId(fromId);
        gift.setToId(toId);
        gift.setGet(false);
        gift.setLastTime(System.currentTimeMillis() / 1000);
        gift.setInsertOption();
        giftMap.put(gift.getGiftId(), gift);
        return gift;
    }

    public static RelativesLetter createRelativesLetter(long fromId, long toId) {
        RelativesLetter letter = new RelativesLetter();
        letter.setId(letterId.incrementAndGet());
        letter.setFromId(fromId);
        letter.setToId(toId);
        letter.setCreateTime(System.currentTimeMillis() / 1000);
        letter.setShow(false);
        letter.setDelete(false);
        letter.setInsertOption();
        synchronized (letterMap) {
            letterMap.put(letter.getId(), letter);
        }
        return letter;
    }

    /**
     * 跨服亲家的书信
     */
    public static int writeLetterFromCross(long userId, long relativesId, long relativesServerId, String content, int writeNum) {
        getLogger().info("cross relatives letter {}, {}", userId, relativesId);
        RelativesLetter letter = RelativesMgr.createRelativesLetter(relativesId, userId);
        letter.setContent(content);

        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
        //玩家在线
        if (onlinePlayer != null) {
            //通知来信
            onlinePlayer.getModule(AttributeModule.class).addAttribute(ePlayerAttrType.TotalReceiveLetterCount, 1);
            onlinePlayer.getModule(RelativesModule.class).syncReceiveLetter(letter);

            addCrossLetterNum(userId, relativesId, writeNum);
        }else {
            MarriageMgr.getThreadTaskManger().addTask(0, new AddCrossLetterNumTask(userId, relativesId, relativesServerId, content, writeNum));
        }
        return 0;
    }

    public static void addCrossLetterNum(long userId, long relativesId, int writeNum) {
        RelativesInfo relativesInfo = RelativesMgr.getRelativesInfo(userId, relativesId);
        if(relativesInfo != null) {
            if (relativesInfo.getUserId1() == userId) {
                //relativesInfo.setLetterNum1(relativesInfo.getLetterNum1() + 1);
                relativesInfo.setLetterNum2(writeNum);
            } else {
                //relativesInfo.setLetterNum2(relativesInfo.getLetterNum2() + 1);
                relativesInfo.setLetterNum1(writeNum);
            }
        }
    }

    /**
     * 跨服赠礼
     * @param userId 被赠送的对象
     */
    public static int giveGiftFromCross(long userId, long relativesId, long relativesServerId){
        getLogger().info("cross relatives git {}, {}", userId, relativesId);
        if (checkMaxReceiveOver(userId)){
            //返回消息给赠送发起的玩家
            //todo 直接忽略
            return GameErrorCode.E_RELATIVES_OTHER_RECEIVE_OVER;
        }

        RelativesGift gift = RelativesMgr.createRelativesGift(relativesId, userId);
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        //同步收礼列表
        if (player != null) {
            player.getModule(RelativesModule.class).syncGiveGiftMsg(gift);
        }

        return 0;
    }

    /**
     * 解除跨服亲家
     */
    public static int cancelRelativesBackFromCross(long userId, long relativesId, long relativesServerId) {
        RelativesInfo info = getRelativesInfo(userId, relativesId);
        if(info == null){
            return -1;
        }

        info.setStatus((short) 0);
        info.setMarriageTimes(0);
        info.setLetterNum1(0);
        info.setLetterNum2(0);
        info.setIsShow("0,0");

        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        if(player != null) {
            player.getModule(RelativesModule.class).deleteLetter(relativesId);
            player.getModule(RelativesModule.class).deleteGift(relativesId);
            player.getModule(RelativesModule.class).syncRelativesData();
            player.notifyListener(eGamePlayerEventType.RelativesCount.getValue(), RelativesMgr.getRelativesNum(userId));
        }

        UserInfo userInfo = UserMgr.getUserInfo(userId);
        String serverName = "";
        ServerInfo serverInfo = ServerListMgr.getServerInfo(relativesServerId);
        if(serverInfo != null){
            serverName = ServerLanguageMgr.getContent(serverInfo.getServerName(), userInfo.getLanguage());
        }

        UserBaseInfo userBaseInfo = getCacheOtherServerUserMap().get(relativesId);
        String mailTitle = MultipleLanguageMgr.getContent(MailManager.RELATIVES_CANCEL_TITLE, userInfo.getLanguage());
        String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.RELATIVES_CROSS_CANCEL_CONTENT, userInfo.getLanguage()), serverName, userBaseInfo == null ? "" : userBaseInfo.getNickName());
        MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), "", mailContent, mailTitle);

        if(player != null) {
            RelativesProto.CancelRelativesRespMsg.Builder respMsg = RelativesProto.CancelRelativesRespMsg.newBuilder();
            respMsg.setRet(0);
            player.sendPacket(Protocol.U_RELATIVES_CANCEL, respMsg);
        }

        return 0;
    }

    public static int cancelRelativesFromCross(long userId, long relativesId, long relativesServerId) {
        MarriageMgr.getThreadTaskManger().addTask(0, new CancelRelativesTask(userId, relativesId, relativesServerId, ""));
        return 0;
    }

    /**
     * 成为跨服亲家
     * @param userId 当前玩家
     * @param relativesId 对方玩家
     * @param relativesServerId 对方区服
     * @param relativesUserBaseInfo 对方基本信息
     * @return
     */
    public static int addRelativesFromCross(long userId, long relativesId, long relativesServerId, UserBaseInfo relativesUserBaseInfo) {
        getCacheOtherServerUserMap().put(relativesId, relativesUserBaseInfo);
        getLogger().info("cross relatives req {}, {}", userId, relativesId);
        int ret = 0;
        RelativesProto.CrossAddRelativesRespMsg.Builder respMsg = RelativesProto.CrossAddRelativesRespMsg.newBuilder();
        RelativesProto.CrossAddRelativesReqMsg.Builder addMsg = RelativesProto.CrossAddRelativesReqMsg.newBuilder();
        addMsg.setToServerId(relativesServerId);
        addMsg.setRelativesId(relativesId);
        addMsg.setFromUserId(userId);
        addMsg.setFromServerId(GameServer.getInstance().getServerId());
        UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(userId, addMsg.getFromServerId());
        UserInfo userInfo = UserMgr.getUserInfo(userId);
        addMsg.setBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));

        boolean sendM = false;

        synchronized (locker) {
            int realNum = getRelativesNum(userId);
            if (realNum < GameConfig.RELATIVES_MAX_NUM) {
                getLogger().info("cross relatives start {}, {}", userId, relativesId);
                RelativesInfo relativesInfo = getRelativesInfo(userId, relativesId);
                if (relativesInfo == null || relativesInfo.getStatus() == 1) {
                    getLogger().info("cross relatives error {}, {}", userId, relativesId);
                    return -1;
                } else {

                    //成为亲家
                    relativesInfo.setStatus((short) 1);
                    sendM = true;

                    //如果玩家在线，同步数据
                    GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
                    if (player != null) {
                        player.getModule(RelativesModule.class).syncMarriageData(relativesId, relativesInfo, true);
                        player.notifyListener(eGamePlayerEventType.RelativesCount.getValue(), getRelativesNum(player.getUserId()));
                    }
                    getLogger().info("cross relatives success {}, {}", userId, relativesId);
                }
            } else {
                return -1;
            }
        }

        if (sendM) {
            String serverName = "";
            ServerInfo serverInfo = ServerListMgr.getServerInfo(relativesServerId);
            if (serverInfo != null) {
                serverName = ServerLanguageMgr.getContent(serverInfo.getServerName(), userInfo.getLanguage());
            }
            String mailTitle = MultipleLanguageMgr.getContent(MailManager.RELATIVES_SUCCESS_TITLE, userInfo.getLanguage());
            String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.RELATIVES_CROSS_SUCCESS_CONTENT, userInfo.getLanguage()), serverName, relativesUserBaseInfo.getNickName());
            MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), GameConfig.RELATIVES_MAIL_REWARD, mailContent, mailTitle);
        }

        respMsg.setRet(ret);
        addMsg.setRelativesNum(getRelativesNum(userId));
        respMsg.setReq(addMsg);
        GamePlayerMgr.sendPacket(0, YanQuMessageUtils.buildMessage(Protocol.C_RELATIVES_ADD_BACK, respMsg));
        return 0;
    }

    public static int addRelativesBackFromCross(long userId, long relativesId, long relativesServerId, UserBaseInfo relativesUserBaseInfo) {
        getCacheOtherServerUserMap().put(relativesId, relativesUserBaseInfo);
        getLogger().info("cross relatives back {}, {}", userId, relativesId);
        RelativesInfo relativesInfo = getRelativesInfo(userId, relativesId);
        synchronized (locker) {
            if (relativesInfo == null) {
                getLogger().info("cross relatives back error {}, {}", userId, relativesId);
                return -1;
            }
            relativesInfo.setStatus((short)1);
        }
        getLogger().info("cross relatives back success {}, {}", userId, relativesId);
        UserInfo userInfo = UserMgr.getUserInfo(userId);

        String serverName = "";
        ServerInfo serverInfo = ServerListMgr.getServerInfo(relativesServerId);
        if(serverInfo != null){
            serverName = ServerLanguageMgr.getContent(serverInfo.getServerName(), userInfo.getLanguage());
        }

        //成为亲家
        String mailTitle = MultipleLanguageMgr.getContent(MailManager.RELATIVES_SUCCESS_TITLE, userInfo.getLanguage());
        String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.RELATIVES_CROSS_SUCCESS_CONTENT, userInfo.getLanguage()), serverName, relativesUserBaseInfo.getNickName());
        MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), GameConfig.RELATIVES_MAIL_REWARD, mailContent, mailTitle);

        //如果玩家在线，同步数据
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId);
        if (player != null) {
            player.getModule(RelativesModule.class).syncMarriageData(relativesId, relativesInfo, true);
            player.notifyListener(eGamePlayerEventType.RelativesCount.getValue(), getRelativesNum(player.getUserId()));
        }
        return 0;
    }

    /**
     * 判断是否达到收礼上限
     */
    public static boolean checkMaxReceiveOver(long userId) {
        GamePlayer relativesPlayer = GamePlayerMgr.getOnlinePlayer(userId);
        int times, maxTimes;
        boolean needLoadDb = false;
        if (relativesPlayer == null) {
            needLoadDb = true;
            maxTimes = RelativesMgr.getMaxDayReceiveTravelPower(userId);
        } else {
            maxTimes = RelativesMgr.getMaxDayReceiveTravelPower(relativesPlayer);
        }
        times = RelativesMgr.getDayGiftNum(userId, false, needLoadDb);
        if (times >= maxTimes) {
            return true;
        }
        return false;
    }

    /**
     * 区服成功联姻
     */
    public static void syncMarriageSuccess(long userId1, long userId2) {
        RelativesInfo relativesInfo = addMarriageTimes(userId1, userId2);
        boolean isAddRelatives = false;

        boolean sendM = false;

        synchronized (locker) {
            if (relativesInfo.getStatus() == 0 && relativesInfo.getMarriageTimes() >= GameConfig.RELATIVES_MARRIAGE_NUM) {
                if (getRelativesNum(userId1) < GameConfig.RELATIVES_MAX_NUM && getRelativesNum(userId2) < GameConfig.RELATIVES_MAX_NUM) {
                    relativesInfo.setStatus((short) 1);
                    isAddRelatives = true;

                    sendM = true;
                }
            }
        }

        if (sendM) {
            UserInfo userInfo1 = UserMgr.getUserInfo(userId1);
            UserInfo userInfo2 = UserMgr.getUserInfo(userId2);
            String mailTitle = MultipleLanguageMgr.getContent(MailManager.RELATIVES_SUCCESS_TITLE, userInfo1.getLanguage());
            String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.RELATIVES_SUCCESS_CONTENT, userInfo1.getLanguage()), userInfo2.getNickName());
            MailManager.sendMail(userId1, eMailType.SYSTEM.getValue(), GameConfig.RELATIVES_MAIL_REWARD, mailContent, mailTitle);

            mailTitle = MultipleLanguageMgr.getContent(MailManager.RELATIVES_SUCCESS_TITLE, userInfo2.getLanguage());
            mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.RELATIVES_SUCCESS_CONTENT, userInfo2.getLanguage()), userInfo1.getNickName());
            MailManager.sendMail(userId2, eMailType.SYSTEM.getValue(), GameConfig.RELATIVES_MAIL_REWARD, mailContent, mailTitle);
        }


        //如果玩家在线，同步数据
        GamePlayer player1 = GamePlayerMgr.getOnlinePlayer(userId1);
        if (player1 != null) {
            player1.getModule(RelativesModule.class).syncMarriageData(userId2, relativesInfo, isAddRelatives);
            if(isAddRelatives){
                player1.notifyListener(eGamePlayerEventType.RelativesCount.getValue(), getRelativesNum(player1.getUserId()));
            }
        }

        GamePlayer player2 = GamePlayerMgr.getOnlinePlayer(userId2);
        if (player2 != null) {
            player2.getModule(RelativesModule.class).syncMarriageData(userId1, relativesInfo, isAddRelatives);
            if (isAddRelatives) {
                player2.notifyListener(eGamePlayerEventType.RelativesCount.getValue(), getRelativesNum(player2.getUserId()));
            }
        }
    }

    /**
     * 跨服成功联姻
     */
    public static void syncCrossMarriageSuccess(long userId1, long userId2) {
        RelativesInfo relativesInfo = addMarriageTimes(userId1, userId2);
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userId1);
        if(player != null){
            player.getModule(RelativesModule.class).getRelativesMap().put(userId2, relativesInfo);
        }
        synchronized (locker) {
            if (relativesInfo.getStatus() == 0 && relativesInfo.getMarriageTimes() >= GameConfig.RELATIVES_MARRIAGE_NUM) {
                int relativesNum = getRelativesNum(userId1);
                if (relativesNum < GameConfig.RELATIVES_MAX_NUM) {
                    RelativesProto.CrossAddRelativesReqMsg.Builder reqMsg = RelativesProto.CrossAddRelativesReqMsg.newBuilder();
                    reqMsg.setRelativesId(userId2);
                    reqMsg.setToServerId(getUserServerId(userId2));
                    reqMsg.setFromServerId(GameServer.getInstance().getServerId());
                    reqMsg.setFromUserId(userId1);
                    UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(userId1, GameServer.getInstance().getServerId());
                    reqMsg.setBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    reqMsg.setRelativesNum(getRelativesNum(userId1));
                    GamePlayerMgr.sendPacket(0, YanQuMessageUtils.buildMessage(Protocol.C_RELATIVES_ADD, reqMsg));
                    getLogger().info("cross relatives send {}, {}", userId1, userId2);
                }
            }else {

            }
        }
    }

    public static RelativesInfo addMarriageTimes(long userId1, long userId2) {
        RelativesInfo relativesInfo = getRelativesInfo(userId1, userId2);
        if (relativesInfo == null) {
            RelativesInfo temp = new RelativesInfo();
            temp.setUserId1(userId1);
            temp.setUserId2(userId2);
            temp.setMarriageTimes(0);
            temp.setStatus((short) 0);
            temp.setIsShow("0,0");
            temp.setInsertOption();
            relativesInfo = addRelativesInfo(temp);
        }
        int times = relativesInfo.getMarriageTimes() + 1;
        relativesInfo.setMarriageTimes(times);
        return relativesInfo;
    }

    public static long getUserServerId(long userId){
        long userServerId = 0;
        try {
            userServerId = Long.parseLong(String.valueOf(userId).substring(0, 8));
        }catch (Exception e){
            getLogger().info("userId {} exception", userId);
        }
        return userServerId;
    }

    /**
     * 最大每日赠送亲家体力赠礼
     */
    public static int getMaxDayGiveTravelPower(GamePlayer player){
        int addition = player.getModule(BeautyModule.class).getIdentitySkillAddition(eSkillType.TravelPowerGiftLimitAdd.getValue(), 0);
        addition += CurioMgr.getSkillAdditionBySkillType(eSkillType.CurioTravelGiveAddSkill.getValue(), player, 0);
        return GameConfig.RELATIVES_DAY_GIVE_NUM + addition;
    }

    /**
     * 最大每日领取亲家体力赠礼
     */
    public static int getMaxDayReceiveTravelPower(GamePlayer player){
        int addition = player.getModule(BeautyModule.class).getIdentitySkillAddition(eSkillType.TravelPowerGiftLimitAdd.getValue(), 0);
        addition += CurioMgr.getSkillAdditionBySkillType(eSkillType.CurioTravelGetAddSkill.getValue(), player, 0);
        return GameConfig.RELATIVES_DAY_RECEIVE_NUM + addition;
    }

    /**
     * 最大每日领取亲家体力赠礼（玩家离线时使用）
     */
    public static int getMaxDayReceiveTravelPower(long userId){
        Map<Integer, UserBeauty> beautyMap = UserBeautyBussiness.getUserBeautyMap(userId);
        int addition = SkillMgr.getIdentitySkillAddition(beautyMap, eSkillType.TravelPowerGiftLimitAdd.getValue(), 0);
        return GameConfig.RELATIVES_DAY_RECEIVE_NUM + addition;
    }

    /**
     * 今日赠礼(收礼)次数
     * @param userId
     * @param isGive  true 赠礼次数 | false 收礼次数
     * @return
     */
    public static int getDayGiftNum(long userId, boolean isGive, boolean needLoadDb) {
        if (needLoadDb) {
            loadRelativesGiftFromDb(userId);
        }
        int count = 0;
        int zeroTime = DateHelper.getTodayZeroTime();
        for (RelativesGift gift : giftMap.values()) {
            if(gift.getLastTime() < zeroTime){
                continue;
            }
            if (isGive && gift.getFromId() == userId) {
                count++;
            } else if (!isGive && gift.getToId() == userId) {
                // 判断是否为亲家,如果不是亲家且礼物未领取
                if (!relativesMap.containsKey(userId)) {
                    continue;
                }
                Map<Long, RelativesInfo> relativesInfoMap = relativesMap.get(userId);
                if (!gift.isGet()) {
                    if (!relativesInfoMap.containsKey(gift.getFromId()) || relativesInfoMap.get(gift.getFromId()).getStatus() == 0) {
                        continue;
                    }
                }
                count++;
            }
        }
        return count;
    }

    public static void seeLetter(long letterId) {
        RelativesLetter letter = letterMap.get(letterId);
        if (letter != null) {
            letter.setShow(true);
        }
    }

    public static void removeGiftData(long giftId) {
        if (giftMap.containsKey(giftId)) {
            giftMap.remove(giftId);
        }
    }

    public static Map<Long, UserBaseInfo> getCacheOtherServerUserMap() {
        return cacheOtherServerUserMap;
    }

    public static void addToFetch(long userId){
        synchronized (todoGetUserSet){
            todoGetUserSet.add(userId);
        }
    }

    public static void fetchCrossRelativesUserInfo(){
        Set<Long> temp;
        synchronized (todoGetUserSet){
            if(todoGetUserSet.size() == 0){
                return;
            }
            temp = new HashSet<>(todoGetUserSet);
            if(cacheOtherServerUserMap.size() > 0) {
                todoGetUserSet.clear();
            }
        }

        Map<Long, List<Long>> serverUserMap = new HashMap<>();
        for (long userId : temp) {
            long serverId = getUserServerId(userId);
            if(serverId == GameServer.getInstance().getServerId()){
                continue;
            }
            if(!serverUserMap.containsKey(serverId)){
                serverUserMap.put(serverId, new ArrayList<>());
            }
            serverUserMap.get(serverId).add(userId);
        }

        for (Map.Entry<Long, List<Long>> entry : serverUserMap.entrySet()) {
            long serverId = entry.getKey();
            RelativesProto.CrossGetUserBaseInfoReqMsg.Builder reqMsg = null;
            List<Long> userList = entry.getValue();
            int k = 0;
            for (int i = 0; i < userList.size(); i++) {
                if(k == 0){
                    reqMsg = RelativesProto.CrossGetUserBaseInfoReqMsg.newBuilder();
                    reqMsg.setFromServerId(GameServer.getInstance().getServerId());
                    reqMsg.setServerId(serverId);
                }
                long userId = userList.get(i);
                reqMsg.addUserId(userId);
                k++;
                if(k == 100 || i == userList.size() - 1){
                    k = 0;
                    GamePlayerMgr.sendPacket(0, YanQuMessageUtils.buildMessage(Protocol.C_RELATIVES_GET_USER_INFO, reqMsg));
                }
            }
        }
    }
}
